package com.tjetc.service.Impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConstants;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeCancelRequest;
import com.alipay.api.request.AlipayTradeCloseRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeCloseResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;
import com.sun.org.apache.xpath.internal.operations.Or;
import com.tjetc.common.AlipayInfo;
import com.tjetc.common.JsonResult;
import com.tjetc.common.MerchantDeploymentInfo;
import com.tjetc.dao.*;
import com.tjetc.entity.Admin;
import com.tjetc.entity.Merchant;
import com.tjetc.entity.Order;
import com.tjetc.entity.User;
import com.tjetc.enums.AlipayTradeState;
import com.tjetc.service.AlipayService;
import com.tjetc.service.RefundService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class AlipayServiceImpl implements AlipayService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private MerchantMapper merchantMapper;

    @Autowired
    private DishMapper dishMapper;

    @Autowired
    private AlipayInfo alipayInfo;

    @Autowired
    MerchantDeploymentInfo merchantDeploymentInfo;

    @Autowired
    private AlipayClient alipayClient;

    @Autowired
    private RefundMapper refundMapper;

    @Autowired
    private AdminMapper adminMapper;

    /**
     *   支付宝完成支付异步回调接口
     * @param params 支付宝端支付完成之后返回的参数
     * @return 返回JsonResult给前端显示
     */
    @Transactional
    @Override
    public JsonResult finish(Map<String, String> params) {
        try {
            boolean signVerified = AlipaySignature.rsaCheckV1(params,
                    alipayInfo.getAlipayPublicKey(),
                    AlipayConstants.CHARSET_UTF8,
                    AlipayConstants.SIGN_TYPE_RSA2); //调用SDK验证签名
            if(!signVerified){
                // TODO 验签失败则记录异常日志，并在response中返回failure.
                log.error("支付成功异步通知验签失败！");
                throw new RuntimeException("支付成功异步通知验签失败！");
            }
            log.info("支付成功异步通知验签成功！");

            // TODO 验签成功后，按照支付结果异步通知中的描述，对支付结果中的业务内容进行二次校验，
            //  校验成功后在response中返回success并继续商户自身业务处理，校验失败返回failure
            String outTradeNo = params.get("out_trade_no");
            log.info("当前订单编号: " + outTradeNo);
            Order orderNumber = orderMapper.selectByNumber(outTradeNo);
            System.out.println(orderNumber);
            // 如果查询得到的订单号是数据库中存在的订单
            if(orderNumber == null) {
                log.error("支付成功，但是订单不存在");
                throw new RuntimeException("支付成功，但是订单不存在");
            }
            // 判断total_amount是否确实为该订单的实际金额（商户订单确定的金额）
            String totalAmount = params.get("total_amount");
            int totalAmountInt = new BigDecimal(totalAmount).multiply(new BigDecimal("100")).intValue();
            int totalFeeInt = orderNumber.getAmount().multiply(new BigDecimal("100")).intValue();
            if(totalFeeInt != totalAmountInt) {
                throw new RuntimeException("支付成功，但是金额异常");
            }
            /*          校验完成         */
            /*     下面写服务器业务逻辑    */
            // 如果确实存在则将数据库中对应的字段修改成1（已支付未完成）
            //修改订单状态
            Integer row = orderMapper.changeOrderStatus(orderNumber.getId(),1);
            Admin admin = adminMapper.selectAll().get(0);
            // 每次支付将余额添加到admin表中
            admin.setAmount(admin.getAmount().add(orderNumber.getAmount()));
            orderNumber.setAlipayId(params.get("trade_no"));
            orderMapper.update(orderNumber);
            Long adminTest = adminMapper.updateByAdmin(admin);// 更新admin
            System.out.println("row"+row);
            if(row!=1 || adminTest != 1){
                throw new RuntimeException("订单状态或者添加余额修改失败");
            }
            //将订单推送到商家端
            //发出http请求 商家端api，把订单id传输给商家的controller，进行websocket通知商家端页面下单成功
            //requestMerchant(orderId);
            requestMerchant(orderNumber.getId());

            return new JsonResult<>(0, "",  orderMapper.changeOrderStatus(orderNumber.getId(), 1)); // 将订单的状态设置为待完成
            /*            end           */
        } catch (Exception e) {
            log.error("支付成功异步通知失败！");
            e.printStackTrace();
        }
        return new JsonResult<>(1, "支付成功异步通知失败！", null);
    }

    /**
     * 取消对应orderId的订单，并且删除refund中的对应值
     * @param refundId 退款请求id
     * @param reason 退款原因
     * @return 返回结果
     */
    @Transactional
    @Override
    public JsonResult refund(Integer refundId, String reason) {
        // 审计日
        Integer orderId = refundMapper.selectById(refundId).getOrderId();
        Order order = orderMapper.selectByOrderId(orderId);
        if(order == null) {
            throw new RuntimeException("订单不存在");
        }
        if(order.getStatus() != 5 && order.getStatus() != 6) {
            throw new RuntimeException("退款的订单不能是已支付或者已经退款状态");
        }
        // 调用当前业务方法的请求参数
        AlipayTradeRefundRequest alipayTradeRefundRequest = new AlipayTradeRefundRequest();
        // 组装当前业务的请求参数
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", order.getNumber());
        bizContent.put("refund_amount", order.getAmount());
        bizContent.put("refund_reason", reason);

        alipayTradeRefundRequest.setBizContent(bizContent.toString());

        // 执行请求 调用支付宝接口
        try {
            AlipayTradeRefundResponse response = alipayClient.execute(alipayTradeRefundRequest);
            if(response.isSuccess()){
                log.info("调用成功，返回结果 ====> " + response.getBody());
                // 更新订单状态
                order.setCheckoutTime(LocalDateTime.now()); // 设置为当前已经完成订单
                order.setStatus(-1);
                Admin admin = adminMapper.selectAll().get(0);
                admin.setAmount(admin.getAmount().subtract(order.getAmount()));

                int update = orderMapper.update(order);
                int delete1 = refundMapper.delete(refundId);
                Long update1 = adminMapper.updateByAdmin(admin);
                if(update <= 0 || delete1 <= 0 || update1 <= 0) {
                    throw new RuntimeException("删除记录失败");
                }
            } else {
                throw new RuntimeException("调用支付宝接口退款失败");
            }
        } catch (AlipayApiException e) {
            throw new RuntimeException("调用支付宝接口退款失败");
        }
        return new JsonResult(0, "", true);
    }

    /**
     * 用户关闭订单调用函数
     * @param orderId
     * @return
     */
    @Transactional
    @Override
    public JsonResult close(Integer orderId) {
        log.info("调用用户关闭订单 ===> {}", orderId);
        Order order = orderMapper.selectByOrderId(orderId);
        if(order == null) {
            throw new RuntimeException("订单不存在");
        }
        AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
        JSONObject btzContent = new JSONObject();
        btzContent.put("out_trade_no", order.getNumber());
        request.setBizContent(btzContent.toString());
        try {
            AlipayTradeCloseResponse response = alipayClient.execute(request);
            if(response.isSuccess()) {
                // 关闭订单就是将订单删除
                int delete = orderMapper.delete(orderId);
                if(delete == 0) {
                    throw new RuntimeException("订单无法删除");
                }
            } else {
                log.error("订单取消失败，可能原因为用户未扫码支付");
                // 尝试删除
                int delete = orderMapper.delete(orderId);
                if(delete == 0) {
                    throw new RuntimeException("订单不存在或者无法删除");
                }
            }
        } catch (AlipayApiException e) {
            throw new RuntimeException("调用支付宝接口关闭订单失败");
        }
        return new JsonResult(0, "", true);
    }

    @Transactional
    @Override
    public void checkOrderStatus(Integer orderId) {
        LocalDateTime NOW = LocalDateTime.now();

        Order order = orderMapper.selectByOrderId(orderId);

        log.info("核实账单号核实状态 ===> {}", order.getNumber());

        String orderNumber = this.queryOrder(orderId);

        // 订单未创建
        if(orderNumber == null) {
            log.info("核实订单未创建 ===> {}", order.getNumber());
            if(order.getOrderTime().isBefore(NOW.minusMinutes(10))) {
                // 更新本地订单状态
                orderMapper.delete(orderId); // 直接关闭删除订单记录
            }
        } else {
            // 解析查单响应结果
            Gson gson = new Gson();
            HashMap<String, LinkedTreeMap> resultMap = gson.fromJson(orderNumber, HashMap.class);
            LinkedTreeMap alipayTradeQueryResponse = resultMap.get("alipay_trade_query_response");
            // 获得状态
            String trade_status = (String)alipayTradeQueryResponse.get("trade_status");

            if(trade_status.equals(AlipayTradeState.NOTPAY.getType())) {
                // 订单未支付
                if(order.getOrderTime().isBefore(NOW.minusMinutes(10))) {
                    log.info("核实订单未支付 ===> {}", order.getNumber());
                    close(order.getId()); // 调用订单关闭接口
                }
            } else if(trade_status.equals(AlipayTradeState.CLOSED.getType())) {
                // 订单已关闭
                if(order.getOrderTime().isBefore(NOW.minusMinutes(10))) {
                    int delete = orderMapper.delete(orderId);
                    if(delete != 1) {
                        throw new RuntimeException("更新订单状态失败");
                    }
                }
            } else if(trade_status.equals(AlipayTradeState.SUCCESS.getType())) {
                log.info("核实订单已支付 ===> {}", order.getNumber());
                order.setStatus(1);
                Integer update = orderMapper.update(order);
                Admin admin = adminMapper.selectAll().get(0);
                admin.setAmount(admin.getAmount().add(order.getAmount()));
                Long aLong = adminMapper.updateByAdmin(admin);
                if(update != 1 || aLong != 1) {
                    throw new RuntimeException("更新订单状态失败");
                }
            }
        }
    }

    /**
     * 查询订单的状态
     * @param orderId 传入的id
     * @return
     */
    @Transactional
    @Override
    public String queryOrder(Integer orderId) {
        log.info("调用用户查询订单 ===> {}", orderId);
        Order order = orderMapper.selectByOrderId(orderId);
        if(order == null) {
            return null;
        }
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        JSONObject btzContent = new JSONObject();
        btzContent.put("out_trade_no", order.getNumber());
        request.setBizContent(btzContent.toString());
        try {
            AlipayTradeQueryResponse response = alipayClient.execute(request);
            if(response.isSuccess()) {
                log.info("订单查询成功，返回码 ===> " + response.getCode() + "，返回描述 ===> " + response.getBody());
                return response.getBody();
            } else {
                log.info("订单查询失败，判断为订单未创建，返回码 ===> " + response.getCode() + "，返回描述 ===> " + response.getBody());
                // 返回空
                return null;
            }
        } catch (AlipayApiException e) {
            throw new RuntimeException("调用支付宝接口查询订单失败");
        }
    }

    //用于访问merchant的websocket
    private void requestMerchant(Integer orderId) {
        HttpClient httpClient = new HttpClient();
        StringBuffer sb = new StringBuffer();
        sb.append(merchantDeploymentInfo.getSchema()).append("://");
        sb.append(merchantDeploymentInfo.getDomain()).append(":");
        sb.append(merchantDeploymentInfo.getPort()).append("/");
        String url = sb.toString() + "message" + "/push";
        System.out.println(url);
        PostMethod postMethod = new PostMethod(url);
        postMethod.addRequestHeader("accept", "*/*");
        //设置Content-Type，此处根据实际情况确定
        postMethod.addRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        //必须设置下面这个Header
        //添加请求参数
        postMethod.addParameter("orderId", orderId.toString());
        String result = "";
        try {
            int code = httpClient.executeMethod(postMethod);
            if (code == 200) {
                result = postMethod.getResponseBodyAsString();
                System.out.println("result:" + result);
                log.info("订单信息发送商家端api成功");
            } else {
                System.out.println("code=" + code);
                log.error("订单信息发送商家端api失败，响应码非200");
                //throw new RuntimeException("订单信息发送商家端api失败，响应码非200");
            }
        } catch (IOException e) {
            e.printStackTrace();
            log.error("订单信息发送商家端api异常，异常信息：",e.getMessage());
            //throw new RuntimeException("订单信息发送商家端api异常");
        }
    }

}
